/**
 * 打开文件
 * @param file string|buffer 绝对路径或相对工作路径
 * @param opt json|null 选项
 * 		flag: string 打开模式  默认'r':仅读,不创建
 * 			注意: 模式为创建时,仅文件  不会创建目录
 * 		mode: int 创建文件时权限 八进制  默认:0o644
 * 		ign: boolean 不存在是否忽略异常(非创建模式)
 * 			默认false: 抛出异常
 * 		syn: boolean 是否同步操作  默认false:异步
 * @return Promise|object|null  !opt.syn->Promise
 * 		object: stat+fd,full,  null:不存在且ign
 */
$.fsOpen = function (file, opt=null){
	const DEF={mode:0o644,flag:'r',ign:false,syn:false};
	const $FS=require('node:fs'), ERR=(e,o)=>{
		let x = e.code==='ENOENT' || e.code==='ENXIO';
		if(x&&o.ign) return null; $.err('$.fsOpen',e);
	};
	const STAT = stat=>{ // 检测:文件夹报错
		if(!stat || !stat.isDirectory()) return stat;
		$.err('$.fsOpen', 'EISDIR: '+stat.full,{fix:2});
	};
	$.fsOpen = function(file, opt=null){
		opt=$.mix({},DEF,opt); const {flag,mode}=opt;
		if(opt.syn){
			try{
				const fd=$FS.openSync(file,flag,mode);
				const m = $.fsStat(file, {syn:true});
				m.fd=fd;  return STAT(m);
			}
			catch(err){ return ERR(err,opt); }
		}
		const w = $.track(()=>{
			const w=$.fsAsync('open',file,flag,mode);
			return w.then(fd=>{
				const B=m=>{ m.fd=fd; return STAT(m); };
				return $.fsStat(file).then(B);
			});
		});
		return w().catch(err=>ERR(err,opt));
	};
	return $.fsOpen(file, opt);
};
